
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#include <algorithm>
#include <fstream>

#include <cstring>
#include <sstream>
#include <hs/hs.h>
#include "unit/unit.h"
#include "unit/clock.h"
using namespace std;

struct Regex{
    unsigned int id;
    unsigned int flag;
    string expr;
};



vector<Match> vecs;


int main(int argc,char *argv[]) {

    if (argc != 3) {
        fprintf(stderr, "Usage: %s <express-file> <input file>\n", argv[0]);
        return -1;
    }

    char *expr_file = argv[1];
    char * input_file = argv[2];

    hs_database_t *db = nullptr;
    hs_compile_error_t *compile_err = nullptr;
    hs_scratch_t *scratch = nullptr;

    size_t matchCount = 0;

    vector<string> patterns;
    vector<unsigned> flags;
    vector<unsigned> ids;

    // do the actual file reading and string handling
    parseFile(expr_file, patterns, flags, ids);

    // Turn our vector of strings into a vector of char*'s to pass in to
    // hs_compile_multi. (This is just using the vector of strings as dynamic
    // storage.)
    vector<const char*> cstrPatterns;
    for (const auto &pattern : patterns) {
        cstrPatterns.push_back(pattern.c_str());
    }

    cout << "Compiling Hyperscan databases with " << patterns.size()
         << " patterns." << endl;


    hs_error_t err = hs_compile_multi(cstrPatterns.data(),flags.data(),ids.data(),ids.size(),HS_MODE_NOSTREAM, nullptr,&db,&compile_err);//getflags(vec_regexs)

    if(err != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to compile pattern : %s\n",
                 compile_err->message);
        hs_free_compile_error(compile_err);
        return -1;
    }



    if (hs_alloc_scratch(db, &scratch) != HS_SUCCESS) {
        fprintf(stderr, "ERROR: Unable to allocate scratch space. Exiting.\n");
        hs_free_database(db);
        return -1;
    }
    CallBackContext c;

    c.halt = 0;

    unsigned int length;
    char *inputdata = readInputData(input_file,&length);
    if(!inputdata){
        cout<<"release database"<<endl;
    }

    Clock clock;
    clock.start();

    err = hs_scan(db, inputdata,length, 0, scratch, record_cb,
                  (void *)&c);
    if(err != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to scan input buffer. Exiting.\n");
        hs_free_scratch(scratch);
        return -1;
    }
    clock.stop();

    cout<<"matched work done,use(s):"<<clock.seconds()<<endl;



    string data(inputdata);
    for(int id=0;id<c.matches.size();id++)
    {



        int id_rule = c.matches[id].id;
        //find the index of id_rule
        int index=-1;

        std::vector<unsigned>::iterator it = std::find(ids.begin(), ids.end(), id_rule);

        if (it != ids.end())
        {
            index = distance(ids.begin(), it);
        }


        if(flags[index] == HS_FLAG_SOM_LEFTMOST)
        {
            long long startPosition = c.matches[id].from;
            long long endPosition = c.matches[id].to;
            int length=endPosition-startPosition;
            string matchedString=data.substr(startPosition,length);
            cout<<"id_rule: "<<id_rule<<",startPosition:"<<startPosition<<",endPosition:"<<endPosition<<",matchedString:"<<matchedString<<endl;
            vecs.push_back(Match{id_rule,startPosition,endPosition,matchedString});

        }else
        {
            long long endPosition = c.matches[id].to;
            cout<<"!not HS_FLAG_SOM_LEFTMOST Mode!"<<"id_rule: "<<id_rule<<",endPosition:"<<endPosition<<endl;
            vecs.push_back(Match{id_rule,0,endPosition,""});

        }








    }

    hs_free_database(db);
    hs_free_scratch(scratch);

    return 0;




//
//
//
//    string data = "baizhantang@qq.com   ,abcdefxxfoobarrrghabcxdefxteakettleeeeexxxxijklmxxdef, baizhantang@163.com,";
//
//    const char *expr[] = {"abc", "def", "foobar.*gh","teakettle{4,10}","ijkl[mMn]","([a-zA-Z0-9]+@[a-zA-Z0-9]+.[a-zA-Z0-9]+)[\\s,]"};// "(101 & 102 & 103) | (104 & !105)",^[a-zA-Z]+@[a-zA-Z]+,,"ijkl[mMn]","^[a-zA-Z]+@[a-zA-Z]+.[a-zA-Z]+"
//
//    unsigned flags[] = {HS_FLAG_SOM_LEFTMOST, HS_FLAG_SOM_LEFTMOST, HS_FLAG_SOM_LEFTMOST,HS_FLAG_SOM_LEFTMOST,HS_FLAG_SOM_LEFTMOST,HS_FLAG_MULTILINE|HS_FLAG_SOM_LEFTMOST};//HS_FLAG_ALLOWEMPTY|HS_FLAG_DOTALL|HS_FLAG_MULTILINE |HS_FLAG_SOM_LEFTMOST};//HS_FLAG_COMBINATION
//
//    unsigned  ids[] = {101,102,103,104,105,106};
//
//    hs_error_t err = hs_compile_multi(expr,flags,ids,6,HS_MODE_NOSTREAM, nullptr,&db,&compile_err);
//    if(err != HS_SUCCESS)
//    {
//        fprintf(stderr, "ERROR: Unable to compile pattern : %s\n",
//                 compile_err->message);
//        hs_free_compile_error(compile_err);
//        return -1;
//    }
//
//    if (hs_alloc_scratch(db, &scratch) != HS_SUCCESS) {
//        fprintf(stderr, "ERROR: Unable to allocate scratch space. Exiting.\n");
//        hs_free_database(db);
//        return -1;
//    }
//    CallBackContext c;
//
//    c.halt = 0;
//
//    err = hs_scan(db, data.c_str(), data.size(), 0, scratch, record_cb,
//                  (void *)&c);
//    if(err != HS_SUCCESS)
//    {
//        fprintf(stderr, "ERROR: Unable to scan input buffer. Exiting.\n");
//        hs_free_scratch(scratch);
//        return -1;
//    }
//
//
//
//    for(int id=0;id<c.matches.size();id++)
//    {
//
//        int id_rule = c.matches[id].id;
//        long long startPosition = c.matches[id].from;
//        long long endPosition = c.matches[id].to;
//        int length=endPosition-startPosition;
//        string matchedString=data.substr(startPosition,length);
//
//        cout<<"id_rule: "<<id_rule<<",startPosition:"<<startPosition<<",endPosition:"<<endPosition<<",matchedString:"<<matchedString<<endl;
//        vecs.push_back(Match{id_rule,startPosition,endPosition,matchedString});
//
//
//    }
//
//    hs_free_database(db);
//    hs_free_scratch(scratch);


}